home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 10 Scripting / 01 Berger / CodeGen.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-16  |  4.1 KB  |  174 lines

  1. #include <assert.h>
  2.  
  3. #include "CodeGen.H"
  4. #include "PTNode.H"
  5.  
  6.  
  7. CodeGen::CodeGen()
  8. {
  9.   // When this class is instantiated, open the 'out.bin' file.  Obviously, a
  10.   // real compiler would want the user to specify the output file name as a
  11.   // command-line argument.
  12.   out = fopen( "out.bin", "wb" );
  13.   if ( out == NULL ) {
  14.     perror( "out.bin" );
  15.     exit( 1 );
  16.   }
  17. }
  18.  
  19.  
  20. CodeGen::~CodeGen()
  21. {
  22.   // Make sure to close the bytecode stream.
  23.   fclose( out );
  24. }
  25.  
  26.  
  27. void
  28. CodeGen::Gen( PTNodePtr node )
  29. {
  30.   // This function switches on the node's type and passes flow of control off
  31.   // to the proper internal code generator function.  This helper function
  32.   // will recursively call this function for any children that it may have.
  33.  
  34.  
  35.   switch ( node->GetType() ) {
  36.     case Add_PTNodeType:
  37.       GenAdd( AddNodePtr( node ) );
  38.       break;
  39.  
  40.     case Subtract_PTNodeType:
  41.       GenSubtract( SubtractNodePtr( node ) );
  42.       break;
  43.  
  44.     case Multiply_PTNodeType:
  45.       GenMultiply( MultiplyNodePtr( node ) );
  46.       break;
  47.  
  48.     case Divide_PTNodeType:
  49.       GenDivide( DivideNodePtr( node ) );
  50.       break;
  51.  
  52.     case Constant_PTNodeType:
  53.       GenConstant( ConstantNodePtr( node ) );
  54.       break;
  55.  
  56.     case Statement_PTNodeType:
  57.       GenStatement( StatementNodePtr( node ) );
  58.       break;
  59.  
  60.     case Block_PTNodeType:
  61.       GenBlock( BlockNodePtr( node ) );
  62.       break;
  63.  
  64.     default:
  65.       // Some unknown node type!  This shouldn't happen...
  66.       assert( false );
  67.       break;
  68.   }
  69. }
  70.  
  71.  
  72. void
  73. CodeGen::GenAdd( AddNodePtr add )
  74. {
  75.   // All of the basic math nodes have the same format:  Generate the code for
  76.   // the left & right hand expressions, and then emit the proper opcode
  77.   // instruction.  This makes sure that the stack will contain the proper two
  78.   // values to preform the addition, subtraction, etc.
  79.   Gen( add->GetLHS() );
  80.   Gen( add->GetRHS() );
  81.  
  82.   WriteOpcode( Add_Opcode );
  83. }
  84.  
  85.  
  86. void
  87. CodeGen::GenSubtract( SubtractNodePtr subtract )
  88. {
  89.   Gen( subtract->GetLHS() );
  90.   Gen( subtract->GetRHS() );
  91.  
  92.   WriteOpcode( Subtract_Opcode );
  93. }
  94.  
  95.  
  96. void
  97. CodeGen::GenMultiply( MultiplyNodePtr multiply )
  98. {
  99.   Gen( multiply->GetLHS() );
  100.   Gen( multiply->GetRHS() );
  101.  
  102.   WriteOpcode( Multiply_Opcode );
  103. }
  104.  
  105.  
  106. void
  107. CodeGen::GenDivide( DivideNodePtr divide )
  108. {
  109.   Gen( divide->GetLHS() );
  110.   Gen( divide->GetRHS() );
  111.  
  112.   WriteOpcode( Divide_Opcode );
  113. }
  114.  
  115.  
  116. void
  117. CodeGen::GenConstant( ConstantNodePtr constant )
  118. {
  119.   // A constant simply pushes its own value onto the stack.  The Push opcode
  120.   // expects that the next word in the bytecode stream is the value to push
  121.   // onto the stack.
  122.   WriteOpcode( Push_Opcode );
  123.   WriteArg( constant->GetValue() );
  124. }
  125.  
  126.  
  127. void
  128. CodeGen::GenStatement( StatementNodePtr stmt )
  129. {
  130.   // A statement yields its entire work to its expression; however, this
  131.   // expression will leave a value on the stack.  For example, the expression
  132.   // "4+5" will leave the answer "9" as the top-most stack element.  Since
  133.   // this statemnt has been completed, it is save to pop this element off the
  134.   // stack.  It is no longer needed.
  135.   Gen( stmt->GetExpression() );
  136.  
  137.   WriteOpcode( Pop_Opcode );
  138. }
  139.  
  140.  
  141. void
  142. CodeGen::GenBlock( BlockNodePtr block )
  143. {
  144.   // Block nodes do not have any code to generate.  They simply iterate over
  145.   // all their children making sure that their values are generated.
  146.   NodeList::const_iterator i = block->GetChildrenBegin();
  147.   NodeList::const_iterator end = block->GetChildrenEnd();
  148.  
  149.   for ( ; i != end; ++i ) {
  150.     const PTNodePtr node = *i;
  151.  
  152.     Gen( node );
  153.   }
  154. }
  155.  
  156.  
  157. void
  158. CodeGen::WriteOpcode( Opcode op )
  159. {
  160.   // Write out opcodes as if they were an integer.  If the size of the
  161.   // generate bytecode stream is an issue, then you'll want to only
  162.   // write out the smallest amount possible (probably a byte).
  163.   WriteArg( (int)op );
  164. }
  165.  
  166.  
  167. void
  168. CodeGen::WriteArg( int arg )
  169. {
  170.   // Some opcodes (such as Push) expect an argument from the bytecode stream.
  171.   // This function writes out such and argument to the output file.
  172.   fwrite( &arg, sizeof( arg ), 1, out );
  173. }
  174.